package my.study.demo.proxy.myproxy;

import my.study.demo.proxystudy.Test;

import java.lang.reflect.Method;

public class MyProxy {
    public static final String ln = "\r\n";//换行
    private MyInvocationHandler handler;

    public static Object newProxyInstance(MyClassLoader loader,
                                          Class<?>[] interfaces,
                                          MyInvocationHandler h) {

        return null;
    }

    public static String generateProxySrc(Class<?> [] interfaces) {

        StringBuffer s = new StringBuffer();
        s.append(Test.class.getPackage()).append(";").append(ln);

        //引入所需jar包
        addReliance(s, interfaces);

        s.append("public class $MyProxy0 implements ");

        //拼接上implements要实现的接口
        addInterface(s, interfaces);

        //拼接上构造方法方法
        addConstructionMethod(s, interfaces);

        //拼接上要实现的接口方法
        addInterfaceMethods(s, interfaces);




        return s.toString();
    }

    private static void addInterfaceMethods(StringBuffer s, Class<?>[] interfaces) {
        for(Class<?> inter : interfaces) {
            for(Method method : inter.getMethods()) {
                s.append("public ").append(method.getReturnType().getSimpleName()).append(" ").append(method.getName()).append("(");
                StringBuffer sb = new StringBuffer();
                sb.append("new Class[]{");
                for(int i = 0; i < method.getParameterTypes().length; i ++) {
                    s.append(method.getParameterTypes()[i].getSimpleName()).append(" param").append(i).append(",");
                    sb.append(method.getParameterTypes()[i].getName()).append(".class").append(",");
                }
                //判断是否进入了上边的for循环，进入的话需要把最后一个字符逗号去掉
                if(sb.length() > 12) {
                    sb.deleteCharAt(sb.length() - 1);
                    s.deleteCharAt(s.length() - 1);
                }
                s.append(")").append("{").append(ln);
                s.append("try {").append(ln);
//                inter.getMethod();
                s.append("Class<?>[] clazzs=").append(sb).append("};").append(ln).append(ln);
                s.append("Method method = ").append(inter.getName()).append(".class.getMethod(").append("\"").append(method.getName()).append("\", ");
                s.append(sb).append("}").append(");").append(ln);

                //判断是否有返回值。有的话需要强转
                if(!"void".equals(method.getReturnType().getSimpleName())) {
                    s.append("return ");
                    if(!"Object".equals(method.getReturnType().getSimpleName())) {
                        s.append("(").append(method.getReturnType().getSimpleName()).append(")");
                    }
                }

                s.append("this.h.invoke(this, method, clazzs);").append(ln);
                s.append("}catch(Throwable t) {").append(ln);
                s.append("throw new UndeclaredThrowableException(t);").append(ln);
                s.append("}").append(ln);
                s.append("}").append(ln);

            }
        }
        s.append("}").append(ln);
    }

    private static void addConstructionMethod(StringBuffer s, Class<?>[] interfaces) {
        s.append("private MyInvocationHandler h;").append(ln);
        s.append("public $MyProxy0(MyInvocationHandler h) {").append(ln);
        s.append("this.h = h;").append(ln);
        s.append("}").append(ln);
    }

    private static void addInterface(StringBuffer s, Class<?>[] interfaces) {
        for(Class inter : interfaces) {
            s.append(inter.getSimpleName()).append(",");
        }
        s.deleteCharAt(s.length() - 1);
        s.append(" {").append(ln);
    }


    public static void addReliance(StringBuffer s, Class<?> [] interfaces) {
        Package myPackage = null;

        for(Class<?> inter : interfaces) {
            Method[] methods = inter.getMethods();
            for(Method method : methods) {

                //1、根据入参类型添加jar包
                for(Class type : method.getParameterTypes()) {

                    //引入的包不能重复
                    if((myPackage = type.getPackage()) != null && s.indexOf(type.getName()) < 0) {
                        s.append("import ").append(type.getName()).append(";").append(ln);
                    }
                }

                //2、根据返回参数类型添加jar包
                Class<?> returnType =  method.getReturnType();

                //引入的包不能重复
                if((myPackage = returnType.getPackage()) != null && s.indexOf(returnType.getName()) < 0) {
                    s.append("import ").append(returnType.getName()).append(";").append(ln);
                }
            }

            //3、添加接口的jar包
            if((myPackage = inter.getPackage()) !=  null && s.indexOf(inter.getName()) < 0) {
                s.append("import ").append(inter.getName()).append(";").append(ln);
            }
        }

        //4、最后添加反射所需jar包
        s.append("import java.lang.reflect.*;").append(ln).append(ln);
    }

}
